#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <stdarg.h>
#include <stdbool.h>
#include "usart.h"
#include "bsp_log.h"


static int print_number(putc_t putcf, unsigned int num, int base, bool upper, int width, char pad)
{
    char buf[32];
    const char *digits = upper ? "0123456789ABCDEF" : "0123456789abcdef";
    int i = 0, count = 0;

    do {
        buf[i++] = digits[num % base];
        num /= base;
    } while (num);

    while (i < width) {
        if (putcf(pad) == EOF) return -1;
        count++;
        width--;
    }

    while (i--) {
        if (putcf(buf[i]) == EOF) return -1;
        count++;
    }

    return count;
}

static int print_float(putc_t putcf, double val, int precision)
{
    int cnt = 0;

    if (val < 0) {
        if (putcf('-') == EOF) return -1;
        cnt++;
        val = -val;
    }

    int int_part = (int)val;
    double frac_part = val - int_part;

    cnt += print_number(putcf, int_part, 10, false, 0, ' ');

    if (putcf('.') == EOF) return -1;
    cnt++;

    for (int i = 0; i < precision; i++) frac_part *= 10;
    cnt += print_number(putcf, (int)(frac_part + 0.5), 10, false, precision, '0');

    return cnt;
}

static int evprintf(putc_t putcf, const char *fmt, va_list ap)
{
    int cnt = 0;
    if (!putcf || !fmt) return -1;

    while (*fmt) {
        if (*fmt != '%') {
            if (putcf(*fmt++) == EOF) return -1;
            cnt++;
            continue;
        }

        fmt++;  // skip '%'

        // --- 格式解析 ---
        char pad = ' ';
        int width = 0;
        int precision = 6; // default precision for float
        bool long_flag = false;

        // 零填充
        if (*fmt == '0') {
            pad = '0';
            fmt++;
        }

        // 宽度
        while (*fmt >= '0' && *fmt <= '9') {
            width = width * 10 + (*fmt++ - '0');
        }

        // 精度（如 %.2f）
        if (*fmt == '.') {
            fmt++;
            precision = 0;
            while (*fmt >= '0' && *fmt <= '9') {
                precision = precision * 10 + (*fmt++ - '0');
            }
        }

        // 长整型
        if (*fmt == 'l') {
            long_flag = true;
            fmt++;
        }

        // 格式符
        switch (*fmt++) {
            case 'c': {
                char c = (char)va_arg(ap, int);
                if (putcf(c) == EOF) return -1;
                cnt++;
                break;
            }
            case 's': {
                char *s = va_arg(ap, char*);
                while (*s) {
                    if (putcf(*s++) == EOF) return -1;
                    cnt++;
                }
                break;
            }
            case 'd': {
                int n = long_flag ? va_arg(ap, long) : va_arg(ap, int);
                if (n < 0) {
                    if (putcf('-') == EOF) return -1;
                    cnt++;
                    n = -n;
                }
                int ncnt = print_number(putcf, (unsigned int)n, 10, false, width, pad);
                if (ncnt < 0) return -1;
                cnt += ncnt;
                break;
            }
            case 'u': {
                unsigned int n = long_flag ? va_arg(ap, unsigned long) : va_arg(ap, unsigned int);
                int ncnt = print_number(putcf, n, 10, false, width, pad);
                if (ncnt < 0) return -1;
                cnt += ncnt;
                break;
            }
            case 'x':
            case 'X': {
                bool upper = (*(fmt - 1) == 'X');
                unsigned int n = long_flag ? va_arg(ap, unsigned long) : va_arg(ap, unsigned int);
                int ncnt = print_number(putcf, n, 16, upper, width, pad);
                if (ncnt < 0) return -1;
                cnt += ncnt;
                break;
            }
            case 'f': {
                double f = va_arg(ap, double);
                int ncnt = print_float(putcf, f, precision);
                if (ncnt < 0) return -1;
                cnt += ncnt;
                break;
            }
            case '%': {
                if (putcf('%') == EOF) return -1;
                cnt++;
                break;
            }
            default: {
                if (putcf('%') == EOF || putcf(*(fmt - 1)) == EOF) return -1;
                cnt += 2;
                break;
            }
        }
    }
    return cnt;
}

/**
 * @brief 使用自定义 putc 函数输出格式化字符串
 *
 * 该函数根据指定的格式和参数进行格式化，并通过提供的 putc 函数逐字符输出。
 *
 * @param putcf   字符输出函数指针（putc_t）。
 * @param fmt     格式化字符串（类似 printf）。
 * @param ...     需要格式化的附加参数。
 * @return        输出的字符数。
 */
int eprintf(putc_t putcf, const char *fmt, ...)
{
    va_list ap;
    int len;

    va_start(ap, fmt);
    len = evprintf(putcf, fmt, ap);
    va_end(ap);

    return len;
}

